# -*- coding:utf-8 -*-
import json
import random
import re
import textwrap
import time

import requests

# @Time    : 2023/8/31 13:54
# @Author  : zengwenjia
# @Email   : zengwenjia@lingxi.ai
# @File    : sales.py
# @Software: LLM_internal

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
from bot.bot import Bot
from loguru import logger
import asyncio

from bot.insurance_consultant_axinsur.knowledge_question_solution import csv_read
from bot.insurance_consultant_axinsur.knowledge_expand import csv_read as knowledge_expand
from bot.insurance_consultant_axinsur.knowledge_sales_skill import csv_read as SaleSkill
from common import constants
from bot.insurance_consultant_axinsur.agent.user_questioning import QuestioningDisputeResolution
from bot.insurance_consultant_axinsur.agent.conversation_agent import Conversation
from bot.insurance_consultant_axinsur.knowledge_question_solution.knowledge_embedding import BGEQuery as QuestionSolutionAZUREQuery
from bot.insurance_consultant_axinsur.knowledge_sales_skill.knowledge_embedding import BGEQuery as SalesSkillAZUREQuery
from bot.insurance_consultant_axinsur.agent.sales_sop_agent import SalesSop
from bot.insurance_sales_gpt.demo.cache_dict import cache_dict
import tiktoken

logger.add("./log/短险执行日志_{time}.log", retention="1 days")

data_skill = SaleSkill.read_map()

data_map = csv_read.read_map()

data_map.update(data_skill)

data_map_expand = knowledge_expand.read_map()

sop_ = []


class Sales(Bot):
    """销售机器人"""

    knowledge_question_solution_query = QuestionSolutionAZUREQuery()
    knowledge_question_solution_query.load_knowledge_base()

    knowledge_sale_skill_query = SalesSkillAZUREQuery()
    knowledge_sale_skill_query.load_knowledge_base()

    def __init__(self, model_name=None):
        self.user_info = ''
        self.solution = ""
        self.max_token_length = 1024 * 2
        self.role_name = "保险规划师"
        self.business_background = """保险公司:泰康保险
销售产品:百万医疗短险
购买领取方式:通过"星火保"公众号"""
        self.model_name = "gpt"
        self.user_job = ''
        self.process_knowledge = ''
        self.multi_knowledge = ''
        self.user_question = ''
        self.skill = ''
        self.sop = ''
        self.content = ''
        self.underwriting = ''
        self.count_token = 0
        self.max_agent_token = 0
        self.voice_num_dict = {}

    def get_token_count(self, input_str, res_str):
        env = tiktoken.encoding_for_model('gpt-4')
        return len(env.encode(input_str + res_str))

    def format_conversation_history(self, conversation_context, max_token_length=None):
        dialogue_history = ""
        if (not max_token_length) or (max_token_length > self.max_token_length):
            max_token_length = self.max_token_length
        # 倒序遍历record_list
        for record in conversation_context[::-1]:
            next_dialogue_history = dialogue_history
            if record['role'] == constants.ROLE_USER:
                next_dialogue_history = "用户:" + record["content"] + "\n" + dialogue_history
            elif record['role'] == constants.ROLE_ASSISTANT:
                next_dialogue_history = self.role_name + ":" + record["content"] + "\n" + dialogue_history
            if len(next_dialogue_history) > max_token_length:
                break
            else:
                dialogue_history = next_dialogue_history
        return dialogue_history

    async def get_user_question(self):
        try:
            questioning_dispute_resolution = QuestioningDisputeResolution(self.role_name, self.conversation_history_str,
                                                                          self.user_base_info)
            self.user_question = await questioning_dispute_resolution.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(questioning_dispute_resolution.prompt, self.user_question)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-用户疑义是:{self.user_question},本次消耗token:{token_size}")
            if self.user_question not in ('用户无问题', '用户无问题。'):
                # 查询用户疑问知识库
                knowledges = self.knowledge_question_solution_query.search_with_score(self.user_question, top_k=6,
                                                                                      limit_score=1.2)
                i = 1
                pre = 'B'
                for r in knowledges:
                    text = r.metadata.get('text')
                    voice_num = r.metadata.get('voice_num')
                    voice_num_simple = pre + str(i)
                    self.voice_num_dict[voice_num_simple] = voice_num
                    i = i + 1
                    text = text.replace(voice_num, voice_num_simple)
                    self.solution = self.solution + text + "\n"
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.user_question = ""

    async def get_sales_sop(self):
        """
        销售流程
        判断下一步的销售流程节点
        """
        try:
            sales_sop = SalesSop(self.role_name, self.conversation_history_str)
            self.sop = await sales_sop.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(sales_sop.prompt, self.sop)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-销售流程节点是:{self.sop},本次消耗 token:{token_size}")
            if self.sop != "":
                # 查询销售流程知识库
                res = self.knowledge_sale_skill_query.search_with_score(self.sop, top_k=5, limit_score=0.8)
                i = 1
                pre = 'A'
                for r in res:
                    text = r.metadata.get('text')
                    voice_num = r.metadata.get('voice_num')
                    voice_num_simple = pre + str(i)
                    self.voice_num_dict[voice_num_simple] = voice_num
                    i = i + 1
                    text = text.replace(voice_num, voice_num_simple)
                    self.skill = self.skill + text + "\n"
            sop_.append(self.sop)

        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.sop = ""

    async def generate_reply(self):
        """
        查询用户疑问解答话术 以及当前节点销售流程话术 并生成最终话术
        """
        try:
            conversation = Conversation(self.role_name,
                                        self.business_background,
                                        self.conversation_history_str, self.user_question, self.solution,
                                        self.sop,
                                        self.skill,
                                        self.user_job,
                                        self.underwriting)
            result = await conversation.achat_auto_llm(type=self.model_name)
            token_size = self.get_token_count(conversation.prompt, result)
            self.count_token = self.count_token + token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            if token_size > self.max_agent_token:
                self.max_agent_token = token_size
            logger.info(
                f"session_id:{self.session_id},content:{self.content},agent-话术生成是:{result},本次消耗token是:{token_size}")
            logger.info(
                f"session_id:{self.session_id},本轮对话单个agent消耗最大的token数为{self.max_agent_token},所有agent总共消耗token:{self.count_token}")
            return result
        except Exception as e:
            logger.exception(e)
            return "出错了，我不知道怎么回答你的问题，你可以换个问法试试"

    async def async_reply_web(self, context, session_id, name='王先生',
                              user_base_info='性别:男\n年龄:37\n城市:包头', content=''):
        start_time = time.time()
        conversation = self.format_conversation_history(context)
        conversation.replace('@@quiet@@', '(用户没说话)')
        conversation = re.sub('(\[.*?\])|(\[#.*?#\])', '', conversation)
        self.session_id = session_id
        self.context = context
        self.conversation_history_str = conversation
        self.user_base_info = user_base_info
        self.content = content
        if len(self.context) < 2:
            result_number = "TY01-3C/TY02-A-3C"
        elif self.context[-1] == '(用户没说话)':
            result_number = random.choice(['TY439-1C', 'TY440-1C'])
        else:
            # 用户疑义\销售流程
            user_question_task = asyncio.create_task(self.get_user_question())
            sales_sop_task = asyncio.create_task(self.get_sales_sop())
            await asyncio.gather(user_question_task, sales_sop_task)
            result_number = await self.generate_reply()
        result_number_ = re.findall('([A-Za-z0-9-|/]+)', result_number)
        if result_number_ is None or len(result_number_) == 0:
            logger.error('没有识别到录音编号,模型返回值:{result_number}', result_number=result_number)
            return '没有找到录音编号'
        # result_number = result_number_[0]
        dm_number = ""
        dm_label = []
        number_arr = result_number.split('|')
        result_ = ""
        for number in number_arr:
            number = number.strip()
            number = self.voice_num_dict.get(number, number)
            temp_result = data_map.get(number)
            # 查找可替换的录音编号
            if number in data_map_expand:
                number_random = random.choice(data_map_expand.get(number))
                if number_random is not None:
                    number = number_random['录音编号']
                    logger.info(
                        f"session_id:{self.session_id},录音编号变更 {number_random['原录音编号']} TO {number_random['录音编号']} ,话术变更 {temp_result['话术']} TO {number_random['话术']}")
            dm_number = dm_number + "," + number
            if temp_result is not None:
                result_ += temp_result['话术']
            if temp_result:
                if '动作标签' in temp_result:
                    dm_label.append(temp_result['动作标签'])
            if "?" in result_ or "？" in result_ or '挂机' in dm_label or '转人' in dm_label:
                break
        if result_ is None:
            result_ = result_number
        execution_time = time.time() - start_time
        logger.warning(
            f"session_id:{self.session_id}，执行时间:{execution_time}，录音编号:{result_number},最终生成话术是:{result_}")
        logger.info(f"---------------分割线--------------")
        print(sop_)
        return result_

    def voice_num(self,v_number,code) -> str:
        if '/' not in v_number:
            return v_number
        code = str(code)
        new_code = ','.join(['N-' + code[i:i + 2] for i in range(0, len(code), 2)])
        v_number_list = v_number.split('/')
        result = v_number_list[0] + ',' + new_code + ',' + v_number_list[1]
        return result

    def voice_age(self, v_number, age) -> str:
        try:
            if v_number != 'TY29-3C' and age:
                return v_number
            age = int(age)
            for max_age in [4, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70]:
                if age <= max_age:
                    return 'TY29-3C-' + str(max_age)
            return v_number
        except:
            return v_number

    async def async_reply(self, context, session_id, user_info) -> dict:
        # 最终返回给dm的数据
        global activation_code
        age = None
        if user_info:
            user_base_info = "姓名:" + user_info.get('fullName') + "\n年龄" + str(user_info.get("age"))
            activation_code = user_info.get('activationCodeNumber')
            age = user_info.get("age")
        dm_result = {}
        start_time = time.time()
        conversation = self.format_conversation_history(context)
        conversation.replace('@@quiet@@', '(用户没说话)')
        conversation = re.sub('(\[.*?\])|(\[#.*?#\])', '', conversation)
        self.session_id = session_id
        self.context = context
        self.conversation_history_str = conversation
        self.user_base_info = user_base_info
        if f'cache_user_info:{session_id}' in cache_dict:
            self.user_info = cache_dict[f'cache_user_info:{session_id}']
        if len(self.context) < 2:
            result_number = "TY02-3C"
        elif self.context[-1] == '(用户没说话)':
            result_number = random.choice(['TY439-1C', 'TY440-1C'])
        else:
            # 用户疑义\销售流程
            user_question_task = asyncio.create_task(self.get_user_question())
            sales_sop_task = asyncio.create_task(self.get_sales_sop())
            await asyncio.gather(user_question_task, sales_sop_task)
            result_number = await self.generate_reply()
        result_number_ = re.findall('([A-Za-z0-9-|/]+)', result_number)
        if result_number_ is None or len(result_number_) == 0:
            logger.error('没有识别到录音编号,模型返回值:{result_number}', result_number=result_number)
            return {'reply_text': '没有找到录音编号', 'voice_record': '', 'label': ''}
        # result_number = result_number_[0]
        dm_number = ""
        dm_label = []
        number_arr = result_number.split('|')
        result_ = ""
        for number in number_arr:
            number = number.strip()
            temp_result = data_map.get(number)
            # 查找可替换的录音编号
            if number in data_map_expand:
                number_random = random.choice(data_map_expand.get(number))
                if number_random is not None:
                    number = number_random['录音编号']
                    logger.info(
                        f"session_id:{self.session_id},录音编号变更 {number_random['原录音编号']} TO {number_random['录音编号']} ,话术变更 {temp_result['话术']} TO {number_random['话术']}")
            number = self.voice_num(number,activation_code)
            number = self.voice_age(number, age)
            dm_number = dm_number + "," + number
            if temp_result is not None:
                result_ += temp_result['话术']
            if '动作标签' in temp_result:
                dm_label.append(temp_result['动作标签'])
            if "?" in result_ or "？" in result_ or '挂机' in dm_label or '转人' in dm_label:
                break
        if result_ is None:
            result_ = result_number
        execution_time = time.time() - start_time
        logger.warning(
            f"session_id:{self.session_id}，执行时间:{execution_time}，录音编号:{result_number},最终生成话术是:{result_}")
        logger.info(f"---------------分割线--------------")
        dm_result["reply_text"] = result_
        dm_result["voice_record"] = dm_number[1:]
        dm_result["label"] = ','.join(dm_label)
        return dm_result


def send_message_to_wechat_group(content):
    webhook_url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=46a11f7d-4bdc-4092-a04c-9118f7b3d412'
    headers = {'Content-Type': 'application/json'}
    data = {
        "msgtype": "markdown",
        "markdown": {
            "content": content,
        }
    }
    dumps = json.dumps(data, ensure_ascii=False).replace('<br>', r'\n\n')
    response = requests.post(
        url=webhook_url,
        headers=headers,
        data=dumps.encode('utf-8')
    )


class SaleGPT:
    def reply(self, query, session_id=None, user_base_info=None):
        if session_id not in cache_dict:
            cache_dict[session_id] = []
        conversation_history = cache_dict.get(session_id)
        if len(conversation_history) > 0:
            conversation_dict = {}
            conversation_dict["role"] = "user"
            conversation_dict["content"] = query
            cache_dict[session_id].append(conversation_dict)

        sales = Sales()
        if user_base_info:
            sales.user_base_info = user_base_info
        result = asyncio.run(sales.async_reply_web(conversation_history, session_id, content=query))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result
        cache_dict[session_id].append(conversation_dict)
        return result


def format_conversation_history(conversation_context):
    dialogue_history = []
    for record in conversation_context:
        if record['role'] == constants.ROLE_USER:
            dialogue_history.append('<font color="warning">用户:' + record["content"] + '</font>')
        elif record['role'] == constants.ROLE_ASSISTANT:
            dialogue_history.append('<font color="info">保险销售员:' + record["content"] + '</font>')
    return '<br>'.join(dialogue_history)


if __name__ == '__main__':
    # conversation_history = [{'role': 'assistant', 'content': '哎，您好。哎，您终于接电话了，看到您在泰康有个免费意外险已经领取成功了，但是保单一直没有收到，这样日后也就没办法理赔了，来电也是特意提醒您，稍后会把保单通过短信发给您，您注意查收下好吧？'}, {'role': 'user', 'content': '好的'}, {'role': 'assistant', 'content': '好的，您的家庭意外保障权益已激活，另外考虑现在疾病频发且医疗费用高昂，我们给您限时升级成600万的医疗全险，并且免费赠送您一张价值235元的体检卡，您可以在当地做个全身体检，我带您到我们公众号上看一下，您电话不要挂，然后把微信打开，我带您看下，（停顿下）微信打开了吧？'}, {'role': 'user', 'content': '好的'}, {'role': 'assistant', 'content': '嗯，好的，打开微信之后您看到微信右上角有个圆圈加号了吗？然后现在请您点击一下右上角的加号，然后再点一下添加朋友，在倒数第二行有公众号这三个字，请问您这边有看到吗？'}, {'role': 'user', 'content': '好的'}, {'role': 'assistant', 'content': '接下来您点一下公众号这里，在搜索栏输入“如果有保”，如是假如的如，果是水果的果，有是有没有的有，保是保险的保，如果有保，您输入下，输好之后点下搜索，然后下方会出现如果有保的公众号，看到了吧？'}, {'role': 'user', 'content': '好的'}, {'role': 'assistant', 'content': '嗯，然后您关注下，关注好了之后，在右下角有个我的，您点下，然后第一行有激活码三个字，看到了吧？'}, {'role': 'user', 'content': '好的'}, {'role': 'assistant', 'content': '就是进入公众号，您点下右下角我的，然后第一行有激活码三个字，然后您点下激活码，然后输入您专属激活码xxxxxx（播报6位数激活码），您输入下，输入好了吧？'}, {'role': 'user', 'content': '好的'}, {'role': 'assistant', 'content': '您输入下，输好之后会进入产品页，写着“保额600万，报销无压力，确诊就能赔”看到了吧。'}, {'role': 'user', 'content': '好的'}, {'role': 'assistant', 'content': '嗯，那就没问题，那保单升级之后呢，以后大病小病，大意外小意外就都给您保齐保全了，进口药自费药都能报，然后费用也很轻松，几块钱就可以了，您点下下面的立即投保，然后确认下费用是不是几块钱，您看下，是几块钱吧？'}, {'role': 'user', 'content': '好的'}]
    conversation_history = []
    user_input = ''
    while True:
        sales = Sales()
        result = asyncio.run(sales.async_reply_web(conversation_history, "123", content=user_input))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result
        conversation_history.append(conversation_dict)
        # logger.info('历史对话缓存:{}'.format(conversation_history))
        if '再见' in result or '祝您生活愉快' in result:
            history = format_conversation_history(conversation_history)
            wraps = textwrap.wrap(history, 3900)
            for wrap in wraps:
                send_message_to_wechat_group(wrap)
            break
        user_input = input("请输入用户的对话：")
        conversation_dict = {}
        conversation_dict["role"] = "user"
        conversation_dict["content"] = user_input
        conversation_history.append(conversation_dict)
